package org.anyin.gitee.cloud.center.upms.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.anyin.gitee.cloud.center.upms.convert.SysMenuConvert;
import org.anyin.gitee.cloud.center.upms.enums.UpmsExCodeEnum;
import org.anyin.gitee.cloud.center.upms.model.SysMenu;
import org.anyin.gitee.cloud.center.upms.model.ext.SysMenuExt;
import org.anyin.gitee.cloud.center.upms.repository.SysMenuRepository;
import org.anyin.gitee.cloud.center.upms.service.SysMenuService;
import org.anyin.gitee.cloud.center.upms.service.dto.SysMenuInfoDTO;
import org.anyin.gitee.cloud.center.upms.service.dto.SysMenuNodeDTO;
import org.anyin.gitee.cloud.center.upms.service.dto.SysMenuPageQueryDTO;
import org.anyin.gitee.cloud.center.upms.service.dto.SysMenuSaveDTO;
import org.anyin.gitee.cloud.lib.core.utils.CollectionUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class SysMenuServiceImpl implements SysMenuService {

    @Autowired
    private SysMenuRepository sysMenuRepository;

    @Autowired
    private SysMenuConvert sysMenuConvert;

    @Override
    public Page<SysMenuInfoDTO> page(SysMenuPageQueryDTO param) {
        Page<SysMenuExt> page = new Page<>(param.getPageNo(), param.getPageSize());
        SysMenuExt entity = new SysMenuExt();
        entity.setMenuCode(param.getMenuCode());
        entity.setMenuName(param.getMenuName());
        entity.setParentCode(param.getParentCode());
        entity.setParentName(param.getParentName());
        page = sysMenuRepository.page(page, entity);
        return sysMenuConvert.getSysMenuInfoDTOPage(page);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class, timeout = 60)
    public void create(SysMenuSaveDTO param) {
        // code exist
        SysMenu menu = sysMenuRepository.getByMenuCode(param.getMenuCode());
        if(menu != null){
            throw UpmsExCodeEnum.MENU_CODE_EXIST.getException();
        }
        menu = sysMenuRepository.getByPermission(param.getPermission());
        if(menu != null){
            throw UpmsExCodeEnum.MENU_PERMISSION_EXIST.getException();
        }

        SysMenu entity = sysMenuConvert.getSysMenu(param);
        this.checkParentMenu(entity);
        sysMenuRepository.save(entity);
    }

    private void checkParentMenu(SysMenu entity){
        if(StringUtils.isNotEmpty(entity.getParentCode())){
            SysMenu pMenu = sysMenuRepository.getByMenuCode(entity.getParentCode());
            if(pMenu == null){
                throw UpmsExCodeEnum.MENU_PARENT_NOT_FOUND.getException();
            }
            entity.setParentId(pMenu.getId());
        }
    }

    @Override
    @Transactional(rollbackFor = Throwable.class, timeout = 60)
    public void modify(Long id, SysMenuSaveDTO param) {
        SysMenu menu = sysMenuRepository.getByMenuCode(param.getMenuCode());
        if(menu != null && !menu.getId().equals(id)){
            throw UpmsExCodeEnum.MENU_CODE_EXIST.getException();
        }
        menu = sysMenuRepository.getByPermission(param.getPermission());
        if(menu != null){
            throw UpmsExCodeEnum.MENU_PERMISSION_EXIST.getException();
        }
        SysMenu entity = sysMenuConvert.getSysMenu(param);
        entity.setId(id);
        this.checkParentMenu(entity);
        sysMenuRepository.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class, timeout = 60)
    public void delete(Long id) {
        SysMenuInfoDTO info = this.info(id);
        List<SysMenu> children = sysMenuRepository.getByParentMenuCode(info.getMenuCode());
        if(!CollectionUtil.isEmpty(children)){
            throw UpmsExCodeEnum.MENU_CHILDREN_EXIST.getException();
        }
        // remove role-menu
        sysMenuRepository.removeById(id);
    }

    @Override
    public List<SysMenuNodeDTO> tree() {
        List<SysMenu> all = sysMenuRepository.all();
        if(CollectionUtil.isEmpty(all)){
            return Lists.newArrayList();
        }
        Map<String, SysMenuNodeDTO> map = CollectionUtil.toMap(all, SysMenu::getMenuCode, item -> {
            SysMenuNodeDTO node = new SysMenuNodeDTO();
            node.setValue(item.getMenuCode());
            node.setLabel(item.getMenuName());
            node.setParent(item.getParentCode());
            return node;
        });
        List<SysMenuNodeDTO> list = Lists.newArrayList();
        for(SysMenuNodeDTO menu : map.values()){
            SysMenuNodeDTO node = map.get(menu.getParent());
            if(node == null){
                list.add(menu);
            }else{
                node.addChild(menu);
            }
        }
        return list;
    }

    @Override
    public SysMenuInfoDTO info(Long id) {
        SysMenu menu = sysMenuRepository.getById(id);
        if(menu == null){
            throw UpmsExCodeEnum.MENU_NOT_FOUND.getException();
        }
        SysMenuInfoDTO info = sysMenuConvert.getSysMenuInfoDTO(menu);
        if(menu.getParentId() != null && menu.getParentId() > 0){
            SysMenu parent = sysMenuRepository.getById(menu.getParentId());
            info.setParentName(parent.getMenuName());
        }
        return info;
    }
}
